package pers.cz.netty;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pers.cz.websocket.MessagePushSocketUtils;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * @program: PostGirl-panent
 * @description: 服务端工作线程
 * @author: Cheng Zhi
 * @create: 2022-07-01 14:04
 **/
public class NettyServerWorker implements Runnable{

    Logger logger = LoggerFactory.getLogger(NettyServerWorker.class);

    int port;

    public NettyServerWorker(int port) {
        this.port = port;
    }

    @Override
    public void run() {

        try {
            // 1、声明一个服务器端
            ServerSocketChannel ssc = ServerSocketChannel.open();
            // 2、绑定端口
            //ssc.bind(new InetSocketAddress(JefConfiguration.getInt(NettyItem.NETTY_SERVER_PORT, 8888)));
            ssc.bind(new InetSocketAddress(port));
            ssc.configureBlocking(false);
            // 3、创建聊天buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 4、创建一个轮询器
            Selector selector = Selector.open();
            // 5、将服务端注册到轮询器上，这样轮询器就会关注服务器端的事件
            SelectionKey register = ssc.register(selector, 0, null);
            // 6、告诉轮询器关注新连接
            register.interestOps(SelectionKey.OP_ACCEPT);

            while (true) {

                // 先阻塞，等待有事件再向下执行
                selector.select();
                // 获取到通过轮询器的所有事件
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    iterator.remove();
                    logger.debug("来了一个事件");
                    if (next.isAcceptable()) {
                        logger.debug("是一个连接事件");
                        // 7、从轮询器中获取一个channel
                        ServerSocketChannel channel = (ServerSocketChannel) next.channel();
                        SocketChannel accept = channel.accept();
                        accept.configureBlocking(false);
                        SelectionKey register1 = accept.register(selector, 0, null);
                        register1.interestOps(SelectionKey.OP_READ); // todo 这个可以是其他的

                    } else if (next.isReadable()) {
                        logger.debug("是一个读取事件");
                        try {
                            SocketChannel channel = (SocketChannel) next.channel();
                            ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);

                            StringBuilder messge = new StringBuilder();
                            while (channel.read(byteBuffer1) > 0) {
                                byteBuffer1.flip();
                                messge.append(Charset.forName(StandardCharsets.UTF_8.name()).decode(byteBuffer1));
                            }
                            if (messge.toString().equals("")) {
                                continue;
                            }
                            String content = "realLog|" + messge;
                            MessagePushSocketUtils.sendInfo(content, 0); // 广播消息
                            logger.debug("接收到的消息====>" + messge);

                        } catch (Exception e) {
                            // 这里报错的原因是服务端在处理客户端数据时，客户端断开了连接
                            //logUtil.error("发生了一点意外");
                            next.cancel();
                        }
                        //byteBuffer.clear();
                    } else if (next.isWritable()) {
                        logger.debug("是一个写入事件");
                        SocketChannel channel = (SocketChannel) register.channel();
                        channel.write(StandardCharsets.UTF_8.encode("你好"));
                    } else {
                        logger.debug("不认识的事件，取消处理，防止一直轮询通知");
                        next.cancel();
                    }
                }

            }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}
